#!/usr/bin/python

import xmlrpclib
import subprocess
import re
import copy
#import xml.etree.cElementTree as et
import socket
import time
import struct

api_server = xmlrpclib.ServerProxy('https://www.planet-lab.org/PLCAPI/', allow_none=True)

# Create an empty dictionary (XML-RPC struct)
auth = {}
# Specify password authentication
auth['AuthMethod'] = 'password'
# Username and password
auth['Username'] = 'nicklausrhodes@gmail.com'
auth['AuthString'] = '3pestUC6'

authorized = api_server.AuthCheck(auth)
if authorized:
    print 'We are authorized!'

node_ids = api_server.GetSlices(auth, ["citadel_nrhodes"], ['node_ids'])[0]['node_ids']
temp_node_hostnames = [node['hostname']  for node in api_server.GetNodes(auth, node_ids, ['hostname', 'boot_state']) if (node['boot_state'] == 'boot')]
print temp_node_hostnames
node_hostnames = [x for x in temp_node_hostnames if x not in ['pl-node-1.csl.sri.com', 'ricepl-5.cs.rice.edu']]

#need to filter on number of nodes required
num_nodes_req = 20
node_hostnames = node_hostnames[0:num_nodes_req]

# build latency table data structure
# we will require a hash of hashes type structure where each node has an 
# associated hashtable that takes other node names as args and returns a tuple
# of data about that connection
latency_table = dict()
node_mapping = dict()
count = 1
for nodeA in node_hostnames:
    latency_table[nodeA] = {}
    node_mapping[nodeA] = count
    node_mapping[count] = (nodeA, socket.gethostbyname(nodeA))
    node_mapping[socket.gethostbyname(nodeA)] = nodeA
    count = count + 1
    #for nodeB in node_hostnames:#necessary?
        #latency_table[nodeA][nodeB] = (None, 'false', 'false')#necessary?
print 'Node Mapping'
print node_mapping

#Write Node Mapping to file
nm_f = open('node_mapping', 'w')
for i in range(1, len(node_hostnames) + 1):
    nm_f.write( str(i) + ' ' + 
                node_mapping[i][0] + ' ' + 
                node_mapping[i][1] + '\n')
nm_f.close()

# ssh into each node and run ping for each remaining node
# another option to explore:
# ssh -l <slicename> <machinename> <command>
temp_list = list(node_hostnames) #temporary list to be consumed
temp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for nodeA in node_hostnames:
    print "Accessing: " + nodeA + "\n"
    temp_list.remove(nodeA)
    latency_table[nodeA] = dict()
    #build a list of nodes for each node to ping
    temp_node_list = '5'
    for nodeB in temp_list:
        print "Adding Node to list: " + nodeB
        temp_node_list += socket.inet_aton(node_mapping[node_mapping[nodeB]][1])
        
                
    #oopen a socket and send packet to Node with control bit '5'
    temp_ip = node_mapping[node_mapping[nodeA]][1]
    print "Temp Node List: " + temp_node_list
    i = 1
    while i:
        try:
            temp_sock.sendto(temp_node_list, (temp_ip, 50007))
            #return data [(node ip, latecy), ...]
            lat_data, temp_addr = temp_sock.recvfrom(1024)
            i = 0
        except socket.timeout, msg:
            print msg
        
    i = 0
    while i < len(lat_data):
        temp_node = socket.inet_ntoa(lat_data[i:i+4])
        temp_lat = struct.unpack('d', lat_data[i+4:i+12])[0]
        print "Latency for Node: " + temp_node + ": " + str(temp_lat)
        latency_table[nodeA][node_mapping[temp_node]] = temp_lat#corrections made on Node side
        i += 12
    
temp_sock.close()
    
# latency_table now contains avg latency data for each edge in the graph

print latency_table

f = open('./kshort/latency_file', 'w')

latency_table_copy = copy.deepcopy(latency_table)
for nodeA, dest in latency_table_copy.iteritems():#necessary??
    for nodeB, values in dest.iteritems():
        one_way_latency = values[1]
        if one_way_latency < 1.00:#maximum resolution of 1 ms
            one_way_latency = 1.00
        one_way_str = str(one_way_latency).split('.')[0]
        f.write("a %d %d %s\n" % (node_mapping[nodeA], node_mapping[nodeB], one_way_str))
        f.write("a %d %d %s\n" % (node_mapping[nodeB], node_mapping[nodeA], one_way_str))

f.close()
